#include <Core.h>
#include "Screenshot.h"


namespace Screenshot
{
    ComPtr<IDXGIOutputDuplication> dxgi_dup;
    ComPtr<ID3D11Device> dx11_device;
    ComPtr<ID3D11DeviceContext> dx11_context;
    ComPtr<ID3D11Texture2D> dx11_storage;
    DXGI_FORMAT screen_format{DXGI_FORMAT_UNKNOWN};
    SCREENSHOT_DESC screen_desc{};
    bool is_init_var{false};

    void shutdown()
    {
        dxgi_dup->Release();
        dx11_device->Release();
        dx11_context->Release();
        dx11_storage->Release();
    }

    bool is_init()
    {
        return is_init_var;
    }



}

void Screenshot::init()
{
    IFFAILED(D3D11CreateDevice(nullptr,D3D_DRIVER_TYPE_HARDWARE,nullptr,0u,nullptr,0u,D3D11_SDK_VERSION,dx11_device.GetAddressOf(),nullptr,dx11_context.GetAddressOf()));
    ComPtr<IDXGIDevice> dx_dxgi_device;
    IFFAILED(dx11_device.As(&dx_dxgi_device));
    ComPtr<IDXGIAdapter> dx_adapter;
    IFFAILED(dx_dxgi_device->GetParent(IID_PPV_ARGS(dx_adapter.GetAddressOf())));
    ComPtr<IDXGIOutput> dx_output0;
    IFFAILED(dx_adapter->EnumOutputs(0u,dx_output0.GetAddressOf()));
    ComPtr<IDXGIOutput1> dx_output1;
    IFFAILED(dx_output0.As(&dx_output1));
    IFFAILED(dx_output1->DuplicateOutput(dx11_device.Get(),dxgi_dup.GetAddressOf()));
    DXGI_OUTDUPL_DESC dup_desc;
    dxgi_dup->GetDesc(&dup_desc);
    screen_desc.width = dup_desc.ModeDesc.Width;
    screen_desc.height = dup_desc.ModeDesc.Height;
    screen_desc.channels = 4u;
    screen_format = dup_desc.ModeDesc.Format;


    screen_desc.data = new unsigned char[screen_desc.size()];

    D3D11_TEXTURE2D_DESC tex_desc{};
    tex_desc.Width = dup_desc.ModeDesc.Width;
    tex_desc.Height = dup_desc.ModeDesc.Height;
    tex_desc.MipLevels = 1u;
    tex_desc.ArraySize = 1u;
    tex_desc.Format = dup_desc.ModeDesc.Format;
    tex_desc.SampleDesc = {1u,0u};
    tex_desc.Usage = D3D11_USAGE_STAGING;
    tex_desc.BindFlags = 0u;
    tex_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    tex_desc.MiscFlags = 0u;
    IFFAILED(dx11_device->CreateTexture2D(&tex_desc,nullptr,&dx11_storage));
    dxgi_dup->ReleaseFrame();
}

Screenshot::SCREENSHOT_DESC Screenshot::cut_frame()
{
    DXGI_OUTDUPL_FRAME_INFO info;
    ComPtr<IDXGIResource> frame;
    while(!frame){
        dxgi_dup->AcquireNextFrame(0u,&info,frame.GetAddressOf());
    }
    ComPtr<ID3D11Texture2D> frame_texture;
    IFFAILED(frame.As(&frame_texture));
    dx11_context->CopyResource(dx11_storage.Get(),frame_texture.Get());
    ComPtr<IDXGISurface> frame_surface;
    IFFAILED(dx11_storage.As(&frame_surface));
    DXGI_MAPPED_RECT data;
    IFFAILED(frame_surface->Map(&data,DXGI_MAP_READ));
    memcpy(screen_desc.data,data.pBits,screen_desc.size());
    IFFAILED(frame_surface->Unmap());
    IFFAILED(dxgi_dup->ReleaseFrame());
    return screen_desc;
}

Screenshot::SCREENSHOT_DESC Screenshot::cut_frame(unsigned int x, unsigned int y, unsigned int w, unsigned int h)
{
    cut_frame();
    SCREENSHOT_DESC desc {};
    desc.channels = 4u;
    desc.width = w;
    desc.height = h;
    desc.init_data();
    for(unsigned int i = y;i < (y+h);i++){
        memcpy(desc.point_data(0u,i-y),screen_desc.point_data(x,i),desc.line_size());
    }
    return desc;
}
